package com.huawei.translate.api;

import com.huawei.translate.model.Renter;
import com.huawei.translate.persistence.RenterRepository;
import com.huawei.translate.provider.MSTranslateProvider;
import com.huawei.translate.service.AuthenticationService;
import com.huawei.translate.utils.SystemConfig;
import com.huawei.translate.vo.AccessTokenGenerateRequest;
import com.huawei.translate.vo.AccessTokenResponse;
import com.huawei.translate.vo.PermissionRequest;
import com.huawei.translate.vo.PermissionResponse;
import io.swagger.annotations.Api;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import java.util.List;
import java.util.UUID;

import static org.springframework.web.bind.annotation.RequestMethod.DELETE;
import static org.springframework.web.bind.annotation.RequestMethod.POST;

@RestController
@RequestMapping("/api/oauth")
@Api(value = "authenticate API", description = "Authentication service")
public class AuthenticateApi {

    private static final Logger LOG = LoggerFactory.getLogger(AuthenticateApi.class);

    @Autowired
    private AuthenticationService authenticationService;

    @Autowired
    private RenterRepository renterRepository;

    @Autowired
    private MSTranslateProvider msTranslateProvider;

    @RequestMapping(method = POST, value = "/generate")
    public ResponseEntity<AccessTokenResponse> generate(@RequestBody AccessTokenGenerateRequest request) {

        long startTime = System.currentTimeMillis();
        AccessTokenResponse responseBody = new AccessTokenResponse();
        if (!isRequestValid(request)) {
            responseBody.setCode(HttpStatus.BAD_REQUEST.value());
            return new ResponseEntity(responseBody, HttpStatus.BAD_REQUEST);
        }

        if (!isUserValid(request)) {
            responseBody.setCode(HttpStatus.FORBIDDEN.value());
            return new ResponseEntity(responseBody, HttpStatus.FORBIDDEN);
        }

        String accessToken = authenticationService.generateAccessToken(request.getAppSecret(), request.getSalt());

        responseBody.setAccessToken(accessToken);
        responseBody.setCode(HttpStatus.OK.value());
        responseBody.setExpireDuration(SystemConfig.getProperty("expiredDuration", "30000"));

        LOG.info("Return Response:" + accessToken + ":" + (System.currentTimeMillis() - startTime));
        return new ResponseEntity(responseBody, HttpStatus.OK);
    }

    @RequestMapping(method = POST, value = "/generate/speech")
    public ResponseEntity<AccessTokenResponse> generateSpeechToken(@RequestBody AccessTokenGenerateRequest request) {

        long startTime = System.currentTimeMillis();
        AccessTokenResponse responseBody = new AccessTokenResponse();
        if (!isRequestValid(request)) {
            responseBody.setCode(HttpStatus.BAD_REQUEST.value());
            return new ResponseEntity(responseBody, HttpStatus.BAD_REQUEST);
        }

        if (!isUserValid(request)) {
            responseBody.setCode(HttpStatus.FORBIDDEN.value());
            return new ResponseEntity(responseBody, HttpStatus.FORBIDDEN);
        }

        String accessToken = msTranslateProvider.getSpeechAccessToken();

        responseBody.setAccessToken(accessToken);
        responseBody.setCode(HttpStatus.OK.value());
        responseBody.setExpireDuration(SystemConfig.getProperty("microsoft.expiredDuration", "600000"));

        LOG.info("Return Speech Response:" + accessToken + ":" + (System.currentTimeMillis() - startTime));
        return new ResponseEntity(responseBody, HttpStatus.OK);
    }


    @RequestMapping(method = POST)
    public ResponseEntity<PermissionResponse> apply(@RequestBody PermissionRequest request) {
        if (!isPermissionRequestValid(request)) {
            return new ResponseEntity(HttpStatus.BAD_REQUEST);
        }

        Renter renter = new Renter();
        renter.setAppKey(request.getAppKey());
        renter.setAppName(request.getAppName());
        renter.setDescription(request.getDescription());
        renter.setAppSecret(UUID.randomUUID().toString());
        renterRepository.save(renter);

        return new ResponseEntity(new PermissionResponse(renter.getAppSecret()), HttpStatus.CREATED);
    }

    @RequestMapping(method = DELETE)
    public ResponseEntity delete() {

        LOG.info("Execute expired access token clean up job");
        long expiredDuration = Long.parseUnsignedLong(SystemConfig.getProperty("expiredDuration", "30000"));
        authenticationService.cleanExpiredToken(System.currentTimeMillis() - expiredDuration);

        return new ResponseEntity(HttpStatus.NO_CONTENT);
    }

    private boolean isPermissionRequestValid(PermissionRequest request) {
        if (request == null || StringUtils.isBlank(request.getAppKey()) || StringUtils.isBlank(request.getAppName())) {
            return false;
        }

        List<Renter> renters = renterRepository.findByAppKey(request.getAppKey().trim());
        if (renters.size() > 0) {
            return false;
        }

        return true;
    }


    private boolean isRequestValid(AccessTokenGenerateRequest request) {
        if (request == null ||  StringUtils.isBlank(request.getAppSecret()) || StringUtils.isBlank(request.getSalt())) {
            return false;
        }
        return true;
    }

    private boolean isUserValid(AccessTokenGenerateRequest request) {
        return renterRepository.findByAppSecret(request.getAppSecret()) != null;
    }
}
